// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: lucasyoo

#include "coin2/strategy/hamm/hamm_order_qty.h"

namespace coin2::strategy::hamm {

OrderQtyGenerator::OrderQtyGenerator(const OrderQtyGeneratorConfig& config, double lot_size)
    : order_qty_(lot_size), is_order_decay_(config.is_order_decay()), eta_(config.eta()) {
  LOG(INFO) << config.DebugString();
}


void OrderQtyGenerator::onBookFeed(
    const double& q,
    const std::pair<double, double>& optimal_bid_ask,
    const TradeCollector* fill_collector,
    const double& lot_size,
    const double& fill_num_hurdle) {
  this->GeneratePrice(optimal_bid_ask);
  this->GenerateOrderQty();
  if (is_order_decay_) {
    if (q > 0) {
      for (auto& qty : bid_qtys_) {
        qty *= std::exp(- q * eta_);
      }
    }
    if (q < 0) {
      for (auto& qty : ask_qtys_) {
        qty *= std::exp(q * eta_);
      }
    }
  }
  for (auto& qty : bid_qtys_) {
    qty *= std::exp(
        -std::max(fill_collector->BuyQty() / lot_size, fill_collector->BuyNum() / fill_num_hurdle));
  }
  for (auto& qty : ask_qtys_) {
    qty *= std::exp(-std::max(
        fill_collector->SellQty() / lot_size,
        fill_collector->SellNum() / fill_num_hurdle));
  }
}

SingleOrderQtyGenerator::SingleOrderQtyGenerator(
    const OrderQtyGeneratorConfig& config,
    double lot_size)
    : OrderQtyGenerator(config, lot_size) {}

// Just Single Bid / Ask Price
void SingleOrderQtyGenerator::GeneratePrice(const std::pair<double, double>& optimal_bid_ask) {
  this->BidPrices().clear();
  this->BidPrices().push_back(optimal_bid_ask.first);
  this->AskPrices().clear();
  this->AskPrices().push_back(optimal_bid_ask.second);
}

// Just Single Bid / Ask Qty
void SingleOrderQtyGenerator::GenerateOrderQty() {
  this->BidQtys().clear();
  this->BidQtys().push_back(this->OrderQty());
  this->AskQtys().clear();
  this->AskQtys().push_back(this->OrderQty());
}

MultiOrderQtyGenerator::MultiOrderQtyGenerator(
    const OrderQtyGeneratorConfig& config,
    double lot_size)
    : OrderQtyGenerator(config, lot_size),
      book_level_(config.book_level()),
      max_spread_bps_(config.book_max_spread_bps()) {}


// Multiple With range max_spread_bps
void MultiOrderQtyGenerator::GeneratePrice(const std::pair<double, double>& optimal_bid_ask) {
  this->BidPrices().clear();
  this->AskPrices().clear();
  double level_spread;
  if (book_level_ != 1) {
    level_spread = (max_spread_bps_ * 1e-4) / (book_level_ - 1);
  } else {
    level_spread = 0;
  }
  for (int i = 0; i < book_level_; ++i) {
    double bid = optimal_bid_ask.first * (1 - level_spread * i);
    double ask = optimal_bid_ask.second * (1 + level_spread * i);
    this->BidPrices().push_back(bid);
    this->AskPrices().push_back(ask);
  }
}

// Just Single Bid / Ask Qty
void MultiOrderQtyGenerator::GenerateOrderQty() {
  this->BidQtys().clear();
  this->AskQtys().clear();
  double sliced_qty;
  if (book_level_ != 1) {
    sliced_qty = this->OrderQty() / (book_level_ - 1);
  } else {
    sliced_qty = this->OrderQty();
  }
  for (int i = 0; i < book_level_; ++i) {
      this->BidQtys().push_back(sliced_qty);
      this->AskQtys().push_back(sliced_qty);
  }
}



}  // namespace coin2::strategy::hamm
